//
//  ParayerTimesManager.m
//  prayertimes
//
//  Created by Serge Zalozniy on 6/9/13.
//  Copyright (c) 2013 Serge Zalozniy. All rights reserved.
//

#import "PrayerTimesManager.h"
#import "Utils.h"

#define SERVICE_URL @"http://www.islamicfinder.org/prayer_service.php"
#define GOLD_SERVICE_URL @"http://www.xmlcharts.com/cache/precious-metals.php?format=json"
#define GEOCODE_SERVOCE_URL @"http://maps.google.com/maps/api/geocode/json?address=%@&sensor=false"


#define COUNTRY_KEY @"country"
#define CITY_KEY @"city"
#define LONGITUDE_KEY @"longitude"
#define LATITUDE_KEY @"latitude"
#define MONTH_KEY @"month"
#define YEAR_KEY @"year"
#define TIMES_TABLE_KEY @"timesTableKey"

#define REQUEST_TYPE_KEY @"requestType"


@implementation PrayerTimesManager

static PrayerTimesManager *sharedInstance = nil;


#pragma mark - Allocators

+(PrayerTimesManager *) sharedInstance {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[PrayerTimesManager alloc] init];
    });
    
    return sharedInstance;
}


#pragma mark - Instance initialization

-(id) init {
    self = [super init];
    if (!self) {
        return nil;
    }
	dataProvider = [DataProvider sharedInstance];
	
	_userData = [[NSMutableDictionary alloc] init];
	[_userData setValue:dataProvider.currentCountry forKey:COUNTRY_KEY];
	[_userData setValue:dataProvider.currentCity forKey:CITY_KEY];
	[_userData setValue:dataProvider.latitude forKey:LATITUDE_KEY];
	[_userData setValue:dataProvider.longitude forKey:LONGITUDE_KEY];
	
	self.delegate = self;
    return self;
}


-(void) dealloc {
	[_userData release];
	
	[super dealloc];
}


#pragma mark - Interface methods

-(void) loadPrayerTimesWithYear:(NSInteger)year month:(NSInteger)month {
    NSMutableDictionary *parameters = [self getParametersForPrayerRequset];
	[parameters setValue:@(month) forKey:MONTH_KEY];
    [parameters setValue:@(year) forKey:YEAR_KEY];
    
	
	NSString *country = [_userData valueForKey:COUNTRY_KEY];
	country = !country ? @"" : country;
	NSString *city = [_userData valueForKey:CITY_KEY];
	city = !city ? @"" : city;
    NSDictionary *userInfo = @{MONTH_KEY : @(month),
                               YEAR_KEY : @(year),
                               COUNTRY_KEY : country,
                               CITY_KEY : city,
							   REQUEST_TYPE_KEY : @(RequestTypePrayers)};
    [self loadFromUrl:SERVICE_URL
           withParams:parameters
          andUserInfo:userInfo];
}


-(void) loadPrayerTimesForNextMonth {
	NSDateComponents *components = [[NSCalendar currentCalendar] components:NSMonthCalendarUnit | NSYearCalendarUnit
																   fromDate:[self nextMonthDate]];

	NSMutableDictionary *parameters = [self getParametersForPrayerRequset];
	[parameters setValue:@(components.month) forKey:MONTH_KEY];
	[parameters setValue:@(components.year) forKey:YEAR_KEY];
	
	NSDictionary *userInfo = @{MONTH_KEY : @(components.month),
                               YEAR_KEY : @(components.year),
                               COUNTRY_KEY : dataProvider.currentCountry,
                               CITY_KEY : dataProvider.currentCity,
							   REQUEST_TYPE_KEY : @(RequestTypePrayersNextMonth)};
    [self loadFromUrl:SERVICE_URL
           withParams:parameters
          andUserInfo:userInfo];
}


-(void) loadGoldPrice {
	NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithCapacity:1];
	NSDictionary *userInfo = @{REQUEST_TYPE_KEY : @(RequestTypeGold)};
    
	[self loadFromUrl:GOLD_SERVICE_URL
		   withParams:parameters
		  andUserInfo:userInfo];
}


-(void) geocodeCounty:(NSString *)country city:(NSString *)city {
	NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithCapacity:1];
	NSDictionary *userInfo = @{REQUEST_TYPE_KEY : @(RequestTypeGeocoding)};
    
	NSString *address = [[NSString stringWithFormat:@"%@,%@", country, city] stringByReplacingOccurrencesOfString:@" " withString:@"+"];
	NSString *url = [NSString stringWithFormat:GEOCODE_SERVOCE_URL, address];
	
	[self loadFromUrl:url
		   withParams:parameters
		  andUserInfo:userInfo];
}


-(PrayerTimeTable *) getPrayerTimeTableForCurrentMonth {
	NSDateComponents *components = [[NSCalendar currentCalendar] components:NSYearCalendarUnit | NSMonthCalendarUnit
																   fromDate:[NSDate date]];
	
	PrayerTimeTable *prayersTimeTable = [[[PrayerTimeTable alloc] init] autorelease];
	[prayersTimeTable unarchiveFromFile:[self getFilePathForDate:[NSDate date]]];
	
	if (prayersTimeTable.$_times.count == 0) {
		[self loadPrayerTimesWithYear:components.year month:components.month];
		return nil;
	}
	
	return prayersTimeTable;
}


-(PrayerTimeTable *) getPrayerTimeTableForNextMonth {
	
	PrayerTimeTable *prayersTimeTable = [[[PrayerTimeTable alloc] init] autorelease];
	[prayersTimeTable unarchiveFromFile:[self getFilePathForDate:[self nextMonthDate]]];
	return prayersTimeTable;
}


-(void) checkTimeTableForNextMonth {
	NSDateComponents *currentDateComponents = [[NSCalendar currentCalendar] components:NSDayCalendarUnit
																   fromDate:[NSDate date]];
	
	PrayerTimeTable *prayersTimeTable = [self getPrayerTimeTableForNextMonth];
	if (currentDateComponents.day > 16 && prayersTimeTable.$_times.count == 0) {
		[self loadPrayerTimesForNextMonth];
	}
}


-(PrayerTime *) getPrayerTimeForToday {
	NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
	[formatter setDateFormat:@"d"];
	
	PrayerTimeTable *timeTable = [self getPrayerTimeTableForCurrentMonth];
	NSPredicate *predicate = [NSPredicate predicateWithFormat:@"day == %@", [formatter stringFromDate:[NSDate date]]];
	NSArray *array = [timeTable.$_times filteredArrayUsingPredicate:predicate];
	return [array lastObject];
}


-(void) saveUserData {
	PrayerTimeTable *prayersTimeTable = [_userData valueForKey:TIMES_TABLE_KEY];
	if ([[_userData valueForKey:CITY_KEY] isEqualToString:@"Birmingham"]) {
		[self changeTimeTableForBirmingham:prayersTimeTable];
	}
	
	[prayersTimeTable archiveToFile:[self getFilePathForDate:[NSDate date]]];
	
	dataProvider.currentCountry = [_userData valueForKey:COUNTRY_KEY];
	dataProvider.currentCity = [_userData valueForKey:CITY_KEY];
	dataProvider.latitude = [_userData valueForKey:LATITUDE_KEY];
	dataProvider.longitude = [_userData valueForKey:LONGITUDE_KEY];
	dataProvider.notificationUpdateDay = @(100);
	
	[[NSNotificationCenter defaultCenter] postNotificationName:PrayerTimesManagerDidSaveUserData
														object:nil];
}


-(void) cancelUserData {
	_userData = nil;
	_userData = [[NSMutableDictionary alloc] init];

	[_userData setValue:dataProvider.currentCountry forKey:COUNTRY_KEY];
	[_userData setValue:dataProvider.currentCity forKey:CITY_KEY];
	[_userData setValue:dataProvider.latitude forKey:LATITUDE_KEY];
	[_userData setValue:dataProvider.longitude forKey:LONGITUDE_KEY];
}


-(NSArray *) getTimesForNotification {
	NSSortDescriptor *sortDescriptor;
	sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"$_day"
												  ascending:YES] autorelease];
	NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
	
	PrayerTimeTable *currentMonth = [self getPrayerTimeTableForCurrentMonth];
	NSArray *currentMonthArray = [currentMonth.$_times sortedArrayUsingDescriptors:sortDescriptors];
	PrayerTimeTable *nextTimeMonth = [self getPrayerTimeTableForNextMonth];
	NSArray *nextMonthArray = [nextTimeMonth.$_times sortedArrayUsingDescriptors:sortDescriptors];

	NSString *am = @" AM";
	NSString *pm = @" PM";
	
	NSDateComponents *currentDateComponents = [[NSCalendar currentCalendar] components:NSDayCalendarUnit
																			  fromDate:[NSDate date]];
	int currentDay = currentDateComponents.day;
	int dayCount = 0;
	NSMutableArray *alarmArray = [NSMutableArray array];
	
	
	if (currentMonthArray.count > 0) {
		for (PrayerTime *dayTime in currentMonthArray) {
			if (dayCount > 10) {
				return alarmArray;
			}
			if ([dayTime.$_day integerValue] < currentDay) {
				continue;
			}
			
			[alarmArray addObject:@{ NOTIFICATION_DATE_KEY :[self parseDateWithYear:currentMonth.$_yaer month:currentMonth.$_month day:dayTime.$_day time:[dayTime.$_fajr stringByAppendingString:am]],
									NOTIFICATION_TITLE_KEY : @"Fajr"}];
			int dhuhrHour = [[[dayTime.$_dhuhr componentsSeparatedByString:@":"] objectAtIndex:0] integerValue];
			[alarmArray addObject:@{ NOTIFICATION_DATE_KEY : [self parseDateWithYear:currentMonth.$_yaer month:currentMonth.$_month day:dayTime.$_day time:[dayTime.$_dhuhr stringByAppendingString:(dhuhrHour == 12 || dhuhrHour <= 5) ? pm : am]],
									NOTIFICATION_TITLE_KEY : @"Dhuhr"}];
			[alarmArray addObject:@{ NOTIFICATION_DATE_KEY : [self parseDateWithYear:currentMonth.$_yaer month:currentMonth.$_month day:dayTime.$_day time:[dayTime.$_asr stringByAppendingString:pm]],
									NOTIFICATION_TITLE_KEY : @"Asr"}];
			[alarmArray addObject:@{ NOTIFICATION_DATE_KEY : [self parseDateWithYear:currentMonth.$_yaer month:currentMonth.$_month day:dayTime.$_day time:[dayTime.$_maghrib stringByAppendingString:pm]],
									NOTIFICATION_TITLE_KEY : @"Maghrib"}];
			[alarmArray addObject:@{ NOTIFICATION_DATE_KEY : [self parseDateWithYear:currentMonth.$_yaer month:currentMonth.$_month day:dayTime.$_day time:[dayTime.$_isha stringByAppendingString:pm]],
									NOTIFICATION_TITLE_KEY : @"Isha"}];
			dayCount ++;
		}
	}
	
	if (nextMonthArray.count > 0) {
		for (PrayerTime *dayTime in nextMonthArray) {
			if (dayCount > 10) {
				return alarmArray;
			}
			if ([dayTime.$_day integerValue] < currentDay) {
				continue;
			}
			
			[alarmArray addObject:@{ NOTIFICATION_DATE_KEY :[self parseDateWithYear:nextTimeMonth.$_yaer month:nextTimeMonth.$_month day:dayTime.$_day time:[dayTime.$_fajr stringByAppendingString:am]],
		  NOTIFICATION_TITLE_KEY : @"Fajr"}];
			int dhuhrHour = [[[dayTime.$_dhuhr componentsSeparatedByString:@":"] objectAtIndex:0] integerValue];
			[alarmArray addObject:@{ NOTIFICATION_DATE_KEY : [self parseDateWithYear:nextTimeMonth.$_yaer month:nextTimeMonth.$_month day:dayTime.$_day time:[dayTime.$_dhuhr stringByAppendingString:(dhuhrHour == 12 || dhuhrHour <= 5) ? pm : am]],
		  NOTIFICATION_TITLE_KEY : @"Dhuhr"}];
			[alarmArray addObject:@{ NOTIFICATION_DATE_KEY : [self parseDateWithYear:nextTimeMonth.$_yaer month:nextTimeMonth.$_month day:dayTime.$_day time:[dayTime.$_asr stringByAppendingString:pm]],
		  NOTIFICATION_TITLE_KEY : @"Asr"}];
			[alarmArray addObject:@{ NOTIFICATION_DATE_KEY : [self parseDateWithYear:nextTimeMonth.$_yaer month:nextTimeMonth.$_month day:dayTime.$_day time:[dayTime.$_maghrib stringByAppendingString:pm]],
		  NOTIFICATION_TITLE_KEY : @"Maghrib"}];
			[alarmArray addObject:@{ NOTIFICATION_DATE_KEY : [self parseDateWithYear:nextTimeMonth.$_yaer month:nextTimeMonth.$_month day:dayTime.$_day time:[dayTime.$_isha stringByAppendingString:pm]],
		  NOTIFICATION_TITLE_KEY : @"Isha"}];
			dayCount ++;
		}
	}

	return alarmArray;
}


#pragma mark - Private methods

-(void) processParsedData:(NSDictionary *)parsedData fromRequest:(ASIHTTPRequest *)request andUserInfo:(NSDictionary *)userInfo {
	RequestType type = [[userInfo valueForKey:REQUEST_TYPE_KEY] integerValue];
	switch (type) {
		case RequestTypePrayers: {
			PrayerTimeTable *prayersTimeTable = [[[PrayerTimeTable alloc] init] autorelease];
			[prayersTimeTable setValuesForKeysWithDictionary:parsedData];
			if (prayersTimeTable.$_times.count > 0) {
				[_userData setValue:prayersTimeTable forKey:TIMES_TABLE_KEY];
				[self saveUserData];
				[[NSNotificationCenter defaultCenter] postNotificationName:PrayerTimesManagerDidFinishTimeRequest
																	object:@{@"status" : @(YES),
															   COUNTRY_KEY:[_userData valueForKey:COUNTRY_KEY],
																  CITY_KEY:[_userData valueForKey:CITY_KEY]}];

			} else {
				[[NSNotificationCenter defaultCenter] postNotificationName:PrayerTimesManagerDidFinishTimeRequest
																	object:@{@"status" : @(NO)}];
			}
			
			break;
		}
		case RequestTypeGold:{
			NSNumber *euroPrice = [[parsedData objectForKey:@"eur"] objectForKey:@"gold"];
			NSNumber *usdPrice = [[parsedData objectForKey:@"usd"] objectForKey:@"gold"];
			NSNumber *gbpPrice = [[parsedData objectForKey:@"gbp"] objectForKey:@"gold"];
			
			dataProvider.goldPriceEURO = euroPrice;
			dataProvider.goldPriceGBP = gbpPrice;
			dataProvider.goldPriceUSD = usdPrice;
			
			NSDateComponents *components = [[NSCalendar currentCalendar] components:NSDayCalendarUnit
																		   fromDate:[NSDate date]];
			dataProvider.goldUpdateDay = @(components.day);
			
			break;
		}
		case RequestTypeGeocoding: {
			
			NSArray *result = [parsedData valueForKey:@"results"];
			if (result.count > 0) {
			 	NSDictionary *address = [result objectAtIndex:0];
				NSDictionary *location = [[address objectForKey:@"geometry"] objectForKey:@"location"];
				
				[_userData setValue:[location objectForKey:@"lat"] forKey:LATITUDE_KEY];
				[_userData setValue:[location objectForKey:@"lng"] forKey:LONGITUDE_KEY];
				
				NSArray *addressComponentsArray = [address objectForKey:@"address_components"];
				int componentsLength = addressComponentsArray.count;
				for (int i = 0; i < componentsLength; i++) {
					NSDictionary *addressComponent = [addressComponentsArray objectAtIndex:i];
					NSString *componentType = [[addressComponent objectForKey:@"types"] objectAtIndex:0];
					if ([componentType isEqualToString:@"country"]) {
						[_userData setValue:[addressComponent valueForKey:@"long_name"] forKey:COUNTRY_KEY];
					}
					if ([componentType isEqualToString:@"locality"]) {
						[_userData setValue:[addressComponent valueForKey:@"long_name"] forKey:CITY_KEY];
					}
				}
				
				if ([[_userData valueForKey:CITY_KEY] isEqualToString:@"Birmingham"]) {
					[_userData setValue: @(-1.9167) forKey:LONGITUDE_KEY];
					[_userData setValue:@(52.4667) forKey:LATITUDE_KEY];
				}
				
				NSDateComponents *components = [[NSCalendar currentCalendar] components:NSDayCalendarUnit
																			   fromDate:[NSDate date]];
				[self loadPrayerTimesWithYear:components.year month:components.month];
			} else {
				[[NSNotificationCenter defaultCenter] postNotificationName:PrayerTimesManagerDidFinishTimeRequest
																	object:@{@"status" : @(NO)}];
			}
			
			break;
		}
		case RequestTypePrayersNextMonth: {
			PrayerTimeTable *prayersTimeTable = [[[PrayerTimeTable alloc] init] autorelease];
			[prayersTimeTable setValuesForKeysWithDictionary:parsedData];
			if (prayersTimeTable.$_times.count > 0) {
				if ([[DataProvider sharedInstance].currentCity isEqualToString:@"Birmingham"]) {
					[self changeTimeTableForBirmingham:prayersTimeTable];
				}
				[prayersTimeTable archiveToFile:[self getFilePathForDate:[self nextMonthDate]]];
			}
			
			break;
		}
			
		default:
			break;
	}
}


-(void) dataProceedFailed:(MDSuperDataSource *)dataSource request:(ASIFormDataRequest *)request {
	UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error"
													message:@"A connection failure occurred"
												   delegate:nil
										  cancelButtonTitle:@"OK"
										  otherButtonTitles:nil];
	[alert show];
	[alert release];
}


-(NSString *) getFilePathForDate:(NSDate *)date {
	NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
	[formatter setDateFormat:@"yyyy_M"];
	NSString *dateString = [formatter stringFromDate:date];
	
	return [[Utils applicationDocumentsDirectory] stringByAppendingPathComponent:dateString];
}


-(NSDate *) nextMonthDate {
	NSDateComponents* dateComponents = [[[NSDateComponents alloc]init] autorelease];
	[dateComponents setMonth:1];
	NSCalendar* calendar = [NSCalendar currentCalendar];
	return [calendar dateByAddingComponents:dateComponents toDate:[NSDate date] options:0];
}


-(NSDate *) parseDateWithYear:(NSNumber *)year month:(NSNumber *)month day:(NSString *)day time:(NSString *)time {
	NSString *dateString = [NSString stringWithFormat:@"%@ %@ %@ %@", year, month, day, time];
	NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
	[dateFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]];
	[dateFormatter setDateFormat:@"yyyy M d h:mm a"];
	
	return  [dateFormatter dateFromString:dateString];
}


-(NSMutableDictionary *) getParametersForPrayerRequset {
	NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
	
	NSTimeZone *timeZone = [NSTimeZone systemTimeZone];
    NSInteger dayLigthOffset = timeZone.daylightSavingTimeOffset / 3600;
	NSInteger timeZoneOffset = (timeZone.secondsFromGMT / 3600) - dayLigthOffset;
    	
	[parameters setValue:@(dayLigthOffset) forKey:@"dayLight"];
    [parameters setValue:@"json" forKey:@"simpleFormat"];
    [parameters setValue:@(YES) forKey:@"monthly"];
    [parameters setValue:@(timeZoneOffset) forKey:@"timezone"];
    
	[parameters setValue:[_userData valueForKey:COUNTRY_KEY] forKey:COUNTRY_KEY];
    [parameters setValue:[_userData valueForKey:CITY_KEY] forKey:CITY_KEY];
    [parameters setValue:[_userData valueForKey:LONGITUDE_KEY] forKey:LONGITUDE_KEY];
    [parameters setValue:[_userData valueForKey:LATITUDE_KEY] forKey:LATITUDE_KEY];
    [parameters setValue:@(1) forKey:@"HanfiShafi"];
	[parameters setValue:@(5) forKey:@"pmethod"];
	[parameters setValue:@(10) forKey:@"fajrTwilight1"];
	[parameters setValue:@(10) forKey:@"fajrTwilight2"];
	[parameters setValue:@(10) forKey:@"ishaTwilight"];
	[parameters setValue:@(30) forKey:@"ishaInterval"];
	[parameters setValue:@(1) forKey:@"dhuhrInterval"];
	[parameters setValue:@(1) forKey:@"maghribInterval"];
	
	return parameters;
}


-(void) changeTimeTableForBirmingham:(PrayerTimeTable *)prayersTimeTable {
	for (PrayerTime *dayTime in prayersTimeTable.$_times) {
		NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
		dateComponents.hour = 1;
		dateComponents.minute = 15;
		NSCalendar *calendar = [NSCalendar currentCalendar];
		NSDate *newDate = [calendar dateByAddingComponents:dateComponents
													toDate:[self parseDateFromString:dayTime.$_maghrib]
												   options:0];
		[dateComponents release];
		NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
		formatter.dateFormat = @"h:mm";
		dayTime.$_isha = [formatter stringFromDate:newDate];
	}
}


-(NSDate *) parseDateFromString:(NSString *)dateString {
	NSDate *currentDate = [NSDate date];
	
	NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
	[dateFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]];
	[dateFormatter setTimeZone:[NSTimeZone systemTimeZone]];
	[dateFormatter setDateFormat:@"MM/dd/yyyy"];
	NSString *currentDateString = [dateFormatter stringFromDate:currentDate];
	
	NSString *parseString = [currentDateString stringByAppendingFormat:@" %@", dateString];
	[dateFormatter setDateFormat:@"MM/dd/yyyy h:mm"];
	return  [dateFormatter dateFromString:parseString];
}


@end
